/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 abstract_bitmap.h

	$Header: /heroes4/abstract_bitmap.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( ABSTRACT_BITMAP_H_INCLUDED )
#define ABSTRACT_BITMAP_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <cassert>

#include "abstract_bitmap_typedef.h"
#include "screen_point.h"
#include "uncopyable.h"

/////////////////////////////////////////////////////////////////////////////
// t_abstract_bitmap class template

template < typename t_pixel_arg >
class t_abstract_bitmap : private t_uncopyable
{
public:
	// Types
	typedef t_pixel_arg t_pixel;

	virtual ~t_abstract_bitmap() = 0;

	// Member functions
	t_pixel *       get_data_ptr() { return m_data_ptr; }
	t_pixel const * get_data_ptr() const { return m_data_ptr; }
	int             get_height() const { return m_height; }
	t_screen_rect   get_rect() const;
	int             get_pitch() const { return m_pitch; }
	int             get_width() const { return m_width; }

	t_pixel * advance_line( t_pixel * data_ptr ) const { return byte_increment( data_ptr, m_pitch ); }
	t_pixel * advance_line( t_pixel * data_ptr, int lines ) const { return byte_increment( data_ptr, m_pitch * lines ); }
	t_pixel const * advance_line( t_pixel const * data_ptr ) const { return byte_increment( data_ptr, m_pitch ); }
	t_pixel const * advance_line( t_pixel const * data_ptr, int lines ) const { return byte_increment( data_ptr, m_pitch * lines ); }
	
	static t_pixel* byte_increment( t_pixel* data, int arg )
	{ 
		return reinterpret_cast<t_pixel*>( reinterpret_cast<char*>(data) + arg );
	}
	static t_pixel const* byte_increment( t_pixel const* data, int arg )
	{
		return reinterpret_cast<t_pixel const*>( reinterpret_cast<char const*>(data) + arg);
	}

protected:
	// Constructors/Destructor
	t_abstract_bitmap();
	t_abstract_bitmap( int width, int height, int pitch, t_pixel * data_ptr );

	// Member functions
	void init( int width, int height, int pitch, t_pixel * data_ptr );

private:
	// Data members
	int			m_width;
	int			m_height;
	int			m_pitch;
	t_pixel *	m_data_ptr;
};

/////////////////////////////////////////////////////////////////////////////
template < typename t_pixel_arg >
inline t_abstract_bitmap< t_pixel_arg >::t_abstract_bitmap()
	:	m_width( 0 ), m_height( 0 ), m_pitch( 0 ), m_data_ptr( 0 )
{
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_pixel_arg >
inline t_abstract_bitmap< t_pixel_arg >::t_abstract_bitmap( int width, int height, int pitch, t_pixel * data_ptr )
	:	m_width( width ), m_height( height ), m_pitch( pitch ), m_data_ptr( data_ptr )
{
	assert( width > 0 );
	assert( height > 0 );
	assert( pitch >= width * sizeof( t_pixel ) );
	assert( data_ptr != 0 );
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_pixel_arg >
t_abstract_bitmap< t_pixel_arg >::~t_abstract_bitmap()
{
	// There's nothing to do here.
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_pixel_arg >
inline void t_abstract_bitmap< t_pixel_arg >::init( int width, int height, int pitch, t_pixel * data_ptr )
{
	assert( width > 0 );
	assert( height > 0 );
	assert( static_cast< unsigned int >( pitch ) >= width * sizeof( t_pixel ) );
	assert( data_ptr != 0 );

	m_width = width;
	m_height = height;
	m_pitch = pitch;
	m_data_ptr = data_ptr;
}

/////////////////////////////////////////////////////////////////////////////
template < typename t_pixel_arg >
inline t_screen_rect t_abstract_bitmap< t_pixel_arg >::get_rect() const
{
	return t_screen_rect( 0, 0, m_width, m_height );
}

/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// t_subbitmap class template

template < typename t_pixel_arg >
class t_subbitmap : public t_abstract_bitmap< t_pixel_arg >
{
public:
	// Constructor
	t_subbitmap( t_abstract_bitmap< t_pixel_arg > & bitmap, t_screen_rect rect );
};

/////////////////////////////////////////////////////////////////////////////
template < typename t_pixel_arg >
t_subbitmap< t_pixel_arg >::t_subbitmap( t_abstract_bitmap< t_pixel_arg > & bitmap, t_screen_rect rect )
{
	rect = intersection( rect, t_screen_rect( 0, 0, bitmap.get_width(), bitmap.get_height() ) );
	init( rect.width(), rect.height(), bitmap.get_pitch(), bitmap.advance_line( bitmap.get_data_ptr(), rect.top ) + rect.left );
}

/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
void draw( t_abstract_bitmap16& dest, t_screen_point const& point,
		   t_abstract_bitmap16 const& source, t_screen_rect const& source_rect );

inline void draw( t_abstract_bitmap16& dest, t_screen_point const& point,
		          t_abstract_bitmap16 const& source )
{
	draw( dest, point, source, source.get_rect() );
}

inline void draw( t_abstract_bitmap16& dest, t_abstract_bitmap16 const& source,
				  t_screen_rect const& source_rect )
{
	draw( dest, t_screen_point(0,0), source, source_rect );
}

inline void draw( t_abstract_bitmap16& dest, t_abstract_bitmap16 const& source )
{
	draw( dest, t_screen_point(0,0), source, source.get_rect() );
}

/////////////////////////////////////////////////////////////////////////////
// fill a rectangle in an abstract bitmap with a specified pixel
/////////////////////////////////////////////////////////////////////////////
void fill( t_abstract_bitmap8& bitmap, t_screen_rect const& rect, t_uint8 pixel );
void fill( t_abstract_bitmap16& bitmap, t_screen_rect const& rect, t_uint16 pixel );
void fill( t_abstract_bitmap24& bitmap, t_screen_rect const& rect, t_pixel_24 pixel );
void fill( t_abstract_bitmap32& bitmap, t_screen_rect const& rect, t_pixel_32 pixel );

/////////////////////////////////////////////////////////////////////////////
// blend a rectangle in an abstract bitmap with a specified pixel using 4 bit alpha
/////////////////////////////////////////////////////////////////////////////
void fill( t_abstract_bitmap16& bitmap, t_screen_rect const& rect, t_uint16 pixel,
		    int alpha );

template <typename t_pixel_arg>
inline void fill( t_abstract_bitmap<t_pixel_arg>& bitmap, t_pixel_arg arg )
{
	fill( bitmap, bitmap.get_rect(), arg );
}

#endif // !defined( ABSTRACT_BITMAP_H_INCLUDED )
